<!DOCTYPE html>
<html lang="en">
<!-- 
两个概念： 变量声明 var ... 函数声明 function(){}
预编译发生在函数执行的前一刻，过程：

1. 创建AO对象

2. 寻找函数的形式参数和变量声明，变量声明和形参名作为AO的属性名，值为undefined

3. 将形参和实参统一，实参替换undefined

4. 寻找函数中的函数声明，函数名作为属性名，值为函数体
-->

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script>
        // 例子1
        function test(a) {
            console.log(a);
            //变量声明
            var a = 123;
            console.log(a);
            //函数声明   
            function a() {}
            console.log(a);
            // 变量声明
            var b = function () {}
            console.log(b);
            //函数声明
            function d() {}
        }
        test(1)

        // 第一步
        ao = {

        }

        //第二步
        ao = {
            //a又是形参 又是变量声明
            a: undefined,

            //  变量声明 var x = 这些都是变量声明
            b: undefined
        }

        //第三步
        ao = {
            a: 1,
            b: undefined
        }

        //第四步之后完成预编译，以这个ao对象开始执行函数
        ao = {
            a: function () {},
            b: undefined,
            d: function () {}
        }

        //开始执行test函数
        function test(a) {
            console.log(a); //根据预编译的结果 输出fn
            var a = 123; // var a在预编译第二步已经执行了， 现在只执行a=123
            /*
             ao 对象发生改变
             ao = {
             	a:123,
             	b:undefined,
             	d:function(){}
             }
            */
            console.log(a); //输出123
            function a() {} //预编译第四部已经看了这代码，所以不再看，ao对象没发生改变
            console.log(a); //输出123
            var b = function () {} //var b预编译第二步的时候已经看过了，现在只进行赋值
            /*
             ao对象发生改变
             ao = {
              a : 123,
              b :function(){},
              d:function(){}
             }
            */
            console.log(b); //输出fn
            function d() {}
        }

        // 例子2
        /* 
            第二步:寻找函数的形式参数和变量声明，变量声明和形参名作为AO的属性名，值为undefined
            ao{
                a:undefined,
                b:undefined,
                c:undefined,
            }
            第三:将形参和实参统一，实参替换undefined
            ao {
                a:1,
                b:4,
                c:undefined
            }
            第四:寻找函数中的函数声明，函数名作为属性名，值为函数体
            ao {
                a:1,
                b:function(){},
                c:undefined,
            }
        */
        function test(a, b) {
            console.log(a); //输出1
            c = 0;
            var c; //预编译阶段已经看过了
            a = 3;
            b = 2;
            console.log(b); //输出2

            function b() {} //这个预编译已经看过了
            console.log(b); // 输出2
        }

        test(1, 4);
    </script>
    <script>
        // 例子三
        /* 1. 创建GO对象

2. 寻找变量声明 赋值undefined
3. 寻找函数中的函数声明，将函数名作为属性名，函数体作为值 */
        /* 
            go{
            a:undefined,
            demo：fn
            // 函数执行的时候 加进来一个f
            f :123
            }
        */
        a = 100;

        function demo(e) {
            /* 
                ao{
                    e:1,
                    c:ud
                    b:ud
                    a:fn
                }
            */
            function a() {}
            arguments[0] = 2;
            console.log(e); //2
            if (a) {
                var b = 123;
                var c = function () {}
            }
            var c;
            a = 10;
            var a;
            console.log(b); //123
            f = 123;
            console.log(c); //fn
            console.log(a); //10
        }
        var a;
        demo(1)
        console.log(a); //100
        console.log(f); //123
    </script>
</head>

<body>

</body>

</html>